#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/sendfile.h>
#include <time.h>
#include <string>
#include <vector>
#include <iostream>
#include <sstream>
#include <fstream>
#include <algorithm>
#include "file_op.hpp"
#include "logger.hpp"

#define SHORT_FILE_SIZE 1000000000

void process_file(InFile &in_file,std::vector<int> &parsed_arr){
    std::vector<int> tmp;
    std::string left,right;
    std::pair<std::string,std::string> res;
    MapIterator it1,it2,it3;
    it1 = in_file.begin();
    it2 = in_file.end();
    if(!it1.is_good() || !it2.is_good()){
        log(ERR,"process_file:cannot create iterators");
        return;
    }
    while(it1 != it2){
        if(!it1.is_good())
            return;
        left = res.second;
        tmp = parse(*it1,it1.get_length(),res);
        if(tmp.size() == 0){
            std::cout << "incorrect or missing output" << std::endl;
            return;
        }
        parsed_arr.insert(parsed_arr.end(),tmp.begin(),tmp.end());
        left += res.first;
        parsed_arr.push_back( atoi( left.c_str() ) );
        
        ++it1;
    }
    left = res.second;
    tmp = parse(*it1,it1.get_length()-1,res);
    parsed_arr.insert(parsed_arr.end(),tmp.begin(),tmp.end());
    left += res.first;
    parsed_arr.push_back( atoi( left.c_str() ) );
    parsed_arr.push_back( atoi( res.second.c_str() ) );
}

int main(int argc, char **argv){
    clock_t t1,t2;
    double elapsed;
    std::vector<int> parsed_arr;
    std::string to_write;
    
    std::pair<std::string,std::string> res;
    
    Logger::instance().init(argv[3],10,true);
    log(INF,"main:Program started");
                
    InFile in_file(argv[1]);
    OutFile out_file(argv[2]);
        
    t1 = get_time();
    if(in_file.get_file_size() < SHORT_FILE_SIZE){
        in_file.map_file();
        parsed_arr = parse(in_file.get_map_ptr(),in_file.get_file_size(),res);
        parsed_arr.push_back(atoi(res.first.c_str()));
        parsed_arr.push_back(atoi(res.second.c_str()));
    }
    else
        process_file(in_file,parsed_arr);
    t2 = get_time();
    elapsed = (t2-t1)/CLOCKS_PER_SEC;
    std::cout << "Reading and parsing file time = " << elapsed << std::endl;
    if(parsed_arr.size() == 0){
        log(ERR,"main:Incorrect or missing input.Aborted");
        return -1;
    }
    t1 = get_time();
    std::sort(parsed_arr.begin(),parsed_arr.end());
    t2 = get_time();
    elapsed = (t2-t1)/CLOCKS_PER_SEC;
    std::cout << "Sorting time = "<< elapsed << std::endl;
    t1 = get_time();
    std::fstream stream(argv[2],std::ios_base::out);
    for(unsigned int i = 0; i < parsed_arr.size();i++)
        stream << parsed_arr[i] << ',';
    t2 = get_time();
    elapsed = (t2-t1)/CLOCKS_PER_SEC;
    std::cout << "Writing time = "<< elapsed << std::endl;
    log(INF,"main:Program exits normally");
    return 0;
}
